#include "stdlib.h"
#include "string.h"
#include "bl_sys.h"
#include <stdio.h>
#include <cli.h>
#include <hosal_uart.h>
#include <blog.h>
#include <hosal_uart.h>
#include <stdint.h>
#include <FreeRTOS.h>
#include <bl_gpio.h>
#include <blog.h>
#include "fpm383c.h"

#define GPIO_LED_PIN 14

/**
 * 控制模块LED灯颜色
 */
uint8_t ps_blueledbuf[16] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x07,0x3C,0x03,0x01,0x01,0x00,0x00,0x49};
uint8_t ps_redledbuf[16] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x07,0x3C,0x02,0x04,0x04,0x02,0x00,0x50};
uint8_t ps_greenledbuf[16] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x07,0x3C,0x02,0x02,0x02,0x02,0x00,0x4C};

/**
 * 休眠指令-设置传感器进入休眠模式
 */
uint8_t ps_sleepbuf[12] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x03,0x33,0x00,0x37};

/**
 * 清空指纹库-删除 flash 数据库中所有指纹模板。
 */
uint8_t ps_emptybuf[12] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x03,0x0D,0x00,0x11};

/**
 * 取消指令-取消自动注册模板和自动验证指纹。如表 2-1 中加密等级设置为 0 或 1 情况下支持此功能
 */
uint8_t ps_cancelbuf[12] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x03,0x30,0x00,0x34};

/**
 * 自动注册模板-一站式注册指纹，包含采集指纹、生成特征、组合模板、存储模板等功能。加密等级设置为 0 或 1 情况下支持此功能。
 */
uint8_t ps_autoenrollbuf[17] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x08,0x31,'\0','\0',0x04,0x00,0x16,'\0','\0'};

/**
 * 验证用获取图像-验证指纹时，探测手指，探测到后录入指纹图像存于图像缓冲区。返回确认码表示：录入成功、无手指等。
 */
uint8_t ps_getimagebuf[12] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x03,0x01,0x00,0x05};

/**
 * 生成特征值-将图像缓冲区中的原始图像生成指纹特征文件存于模板缓冲区
 */
uint8_t ps_getcharbuf[13] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x04,0x02,0x01,0x00,0x08};

/**
 * 搜索指纹-以模板缓冲区中的特征文件搜索整个或部分指纹库。若搜索到，则返回页码。加密等级设置为 0 或 1 情况下支持
 */
uint8_t ps_searchbuf[17] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x08,0x04,0x01,0x00,0x00,0xFF,0xFF,0x02,0x0C};

/**
 * 删除模板-删除 flash 数据库中指定 ID 号开始的N 个指纹模板
 */
uint8_t ps_deletebuf[16] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x07,0x0C,'\0','\0',0x00,0x01,'\0','\0'};

/**
 * 设置名为fpm383c_uart的外设句柄,用来执行串口指令的发送
 */
hosal_uart_dev_t fpm383c_uart = {
       .config = {
           .uart_id = 1,
           .tx_pin = 4, // TXD GPIO
           .rx_pin = 3,  // RXD GPIO
           .baud_rate = 57600,
           .data_width = HOSAL_DATA_WIDTH_8BIT,
           .parity = HOSAL_NO_PARITY,
           .stop_bits = HOSAL_STOP_BITS_1,
           .mode = HOSAL_UART_MODE_POLL,
       },
   };

/**
 * 指纹ID和验证指纹的分数
 */
uint16_t pageID,score;

/**
 * USART串口接收缓冲数组
 */
uint8_t uart_receivebuf[20];

/**
 * 主循环状态标志位
 */
uint8_t scanstatus = 0;

/**
 * @brief 获取状态
 * 
 * @param timeout
 */
void fpm383c_receivedata(uint16_t timeout, uint8_t lenght)
{
	// 轮询fpm383c_uart接收到的字符
	int ret;
	uint8_t uart_receive_len = 0;
	uint8_t receivebuf_cache[20];
	memset(uart_receivebuf, 0xFF, sizeof(uart_receivebuf));
	while(true){
		ret = hosal_uart_receive(&fpm383c_uart, receivebuf_cache, sizeof(receivebuf_cache));
		if (ret > 0) {
			memcpy(uart_receivebuf + uart_receive_len, receivebuf_cache, ret);
			uart_receive_len += ret;
			/* Uart send poll */
			if(uart_receive_len >= lenght){
				uart_receive_len=0;
				break;
			}
		}
		vTaskDelay(1);
	}

}

/**
 * 初始化FPM383C指纹模块
 */
void fpm383c_init(){
    /* Uart init device */
    hosal_uart_init(&fpm383c_uart);
    printf("fpm383c_init\r\n");
}

/**
 * USART串口发送数据
 * @param length 发送数组长度
 * @param fpm383c_databuf 需要发送的功能数组
 */
void fpm383c_senddata(int length, uint8_t fpm383c_databuf[])
{
	hosal_uart_send(&fpm383c_uart, fpm383c_databuf, length);
}

/**
 * 发送休眠指令 确认码=00H 表示休眠设置成功。确认码=01H 表示休眠设置失败。
 */
void fpm383c_sleep(void)
{
	fpm383c_senddata(12, ps_sleepbuf);
}

/**
 * 验证用获取图像
 * @param timeout接收数据的超时时间
 * @return 确认码
 */
uint8_t fpm383c_getimage(uint32_t timeout)
{
	uint8_t tmp;
	fpm383c_senddata(12,ps_getimagebuf);
	fpm383c_receivedata(timeout, 12);
	tmp = (uart_receivebuf[6] == 0x07 ? uart_receivebuf[9] : 0xFF);
	memset(uart_receivebuf,0xFF,sizeof(uart_receivebuf));
	return tmp;
}

/**
 * 将图像缓冲区中的原始图像生成指纹特征文件存于模板缓冲区
 * @param timeout 接收数据的超时时间
 * @return 确认码
 */
uint8_t fpm383c_genchar(uint32_t timeout)
{
	uint8_t tmp;
	fpm383c_senddata(13,ps_getcharbuf);
	fpm383c_receivedata(timeout, 12);
	tmp = (uart_receivebuf[6] == 0x07 ? uart_receivebuf[9] : 0xFF);
	memset(uart_receivebuf,0xFF,sizeof(uart_receivebuf));
	return tmp;
}

/**
 * 发送搜索指纹指令
 * @param timeout 接收数据的超时时间
 * @return 确认码
 */
uint8_t fpm383c_search(uint32_t timeout)
{
	fpm383c_senddata(17,ps_searchbuf);
	fpm383c_receivedata(timeout, 16);
	return (uart_receivebuf[6] == 0x07 ? uart_receivebuf[9] : 0xFF);
}

/**
 * 删除指定指纹指令
 * @param pageID 需要删除的指纹
 * @param timeout 接收数据的超时时间
 * @return 确认码
 */
uint8_t fpm383c_delete(uint16_t pageID,uint32_t timeout)
{
	uint8_t tmp;
	ps_deletebuf[10] = (pageID>>8);
	ps_deletebuf[11] = (pageID);
	ps_deletebuf[14] = (0x15+ps_deletebuf[10]+ps_deletebuf[11])>>8;
	ps_deletebuf[15] = (0x15+ps_deletebuf[10]+ps_deletebuf[11]);
	fpm383c_senddata(16,ps_deletebuf);
	fpm383c_receivedata(timeout, 12);
	tmp = (uart_receivebuf[6] == 0x07 ? uart_receivebuf[9] : 0xFF);
	memset(uart_receivebuf,0xFF,sizeof(uart_receivebuf));
	return tmp;
}

/**
 * 清空指纹库
 * @param timeout 接收数据的超时时间
 * @return 确认码
 */
uint8_t fpm383c_empty(uint32_t timeout)
{
	uint8_t tmp;
	fpm383c_senddata(12,ps_emptybuf);
	fpm383c_receivedata(timeout, 12);
	tmp = (uart_receivebuf[6] == 0x07 ? uart_receivebuf[9] : 0xFF);
	memset(uart_receivebuf,0xFF,sizeof(uart_receivebuf));
	return tmp;
}

/**
 * 发送控制灯光指令
 * @param ps_controlledbuf 不同颜色的协议数据
 * @param timeout 接收数据的超时时间
 * @return 确认码
 */
uint8_t fpm383c_controlled(uint8_t ps_controlledbuf[],uint32_t timeout)
{
	uint8_t tmp;
	fpm383c_senddata(16,ps_controlledbuf);
	fpm383c_receivedata(timeout, 12);
	tmp = (uart_receivebuf[6] == 0x07 ? uart_receivebuf[9] : 0xFF);
	memset(uart_receivebuf,0xFF,sizeof(uart_receivebuf));
	return tmp;
}

/**
 * 验证指纹是否注册
 */
void fpm383c_identify(void)
{
	if(fpm383c_getimage(2000) == 0x00)
	{
		if(fpm383c_genchar(2000) == 0x00)
		{
			bl_gpio_enable_output(GPIO_LED_PIN, 0, 0);
			bl_gpio_output_set(GPIO_LED_PIN, 0);
			if(fpm383c_search(2000) == 0x00)
			{
				score = (int)((uart_receivebuf[10] << 8) + uart_receivebuf[11]);
				printf("success ID: %d \r\n",(int)score);
				fpm383c_controlled(ps_greenledbuf,1000);
		
				bl_gpio_output_set(GPIO_LED_PIN, 1);
				vTaskDelay(pdMS_TO_TICKS(1000));
				bl_gpio_output_set(GPIO_LED_PIN, 0);
				// 重置接收数据缓存
				memset(uart_receivebuf,0xFF,sizeof(uart_receivebuf));
				return;
			}else{
				printf("fail \r\n");
				bl_gpio_output_set(GPIO_LED_PIN, 1);
				vTaskDelay(pdMS_TO_TICKS(1000));
				bl_gpio_output_set(GPIO_LED_PIN, 0);
				// 重置接收数据缓存
				memset(uart_receivebuf,0xFF,sizeof(uart_receivebuf));
				return;
			}
		}
	}
}

/**
 * 自动注册
 * @param pageID 输入需要注册的指纹ID号，取值范围0—59
 * @param timeout 设置注册指纹超时时间，因为需要按压四次手指，建议大于10000（即10s）
 */
void fpm383c_enroll(uint16_t pageID,uint16_t timeout)
{
	blog_info("注册指纹ID: %d\r\n", pageID);
	ps_autoenrollbuf[10] = (pageID>>8);
	ps_autoenrollbuf[11] = (pageID);
	ps_autoenrollbuf[15] = (0x54+ps_autoenrollbuf[10]+ps_autoenrollbuf[11])>>8;
	ps_autoenrollbuf[16] = (0x54+ps_autoenrollbuf[10]+ps_autoenrollbuf[11]);
	fpm383c_senddata(17,ps_autoenrollbuf);
	fpm383c_receivedata(timeout, 14);
	if(uart_receivebuf[9] == 0x00)
	{
		blog_info("指纹注册完成\r\n");
		// 亮绿灯2秒
		fpm383c_controlled(ps_greenledbuf,2000);
		// 重置接收数据缓存
		memset(uart_receivebuf,0xFF,sizeof(uart_receivebuf));
		return;
	}
	else if(timeout == 0)
	{
		// 超时取消注册
		fpm383c_senddata(12,ps_cancelbuf);
		vTaskDelay(pdMS_TO_TICKS(50));
		// 重置接收数据缓存
		memset(uart_receivebuf,0xFF,sizeof(uart_receivebuf));
	}
	// 亮红灯2秒
	fpm383c_controlled(ps_redledbuf,2000);
}
